/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief GIM utilities header file.
 * \author Harri Kukkonen
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef GIM_UTILS_H
#define GIM_UTILS_H

#include <limits.h>
#include <stdio.h>
#include <string>
#include <sstream>
#include <time.h>

#include "ownutils.h"
#include "owndebug.h"
#include "imageutils.h"

namespace gim {

/**
 * Structure that contains a time in microsecond accuracy. Most used operations
 * are overloaded for easier usage: = += -= + -
 */
class time
{
  public:
    time();
    time(const long int sec,
         const long int usec);
    time(const int milliseconds);
    time(const unsigned int milliseconds);
    time(const time &right);
    time(const bool settocurrent);
    time(const bool settocurrent,
         const int milliseconds);
    ~time();
  
    inline long int getSeconds() const { return seconds; }
    inline long int getUSeconds() const { return useconds; }
    
    inline void setSeconds(long int sec) { seconds = sec; }
    inline void setUSeconds(long int usec){ useconds = usec; }
    
    /**
     * Sets the class to current time.
     */
    bool setToCurrent();
    
    /**
     * Sets time to current and adds given time in milliseconds.
     */
    bool setToCurrentPlus(const int milliseconds);
    
    /**
     * Convert and set given time to this class.
     */
    bool setTimeMs(const int milliseconds);
    
    /**
     * Convert and add given time to this class.
     */
    bool addTimeMs(const int milliseconds);
    
    /**
     * Convert and reduce given time from this class.
     */
    bool reduceTimeMs(const int milliseconds);
    
    /**
     * Returns time in class as milliseconds. In case returned value would
     * over- or underflow, INT_MAX or INT_MIN is returned.
     */
    int getTimeMs() const;


    /**
     * Returns time in class as microseconds. In case returned value would
     * over- or underflow, LLONG_MAX or LLONG_MIN is returned.
     */
    long long int getTimeUs() const;


    /**
     * Returns the absolute time in class as milliseconds.  In case
     * the class time is negative, it will be converted to positive.
     * @return                  Number of milliseconds represented by this
     *                          class instance.
     */
    unsigned int getAbsTimeMs(void) const;

    
    /** Convert to string and return the object.
     * 
     * Value is converted to form '%us &uus'. 
     *
     * @return                  String form of time.
     */
    std::string toString(void) const;


    /** Get date as String.
     *
     * The default format for Date string is '%F %T %Z'. Which gives time
     * in format like: "1974-02-01 20:42:03 EET"
     *
     * \note See manual of strftime(3) for information about supported conversion flags.
     * 
     * @param[in] aStrftimeFormat strftime(3) format string to use for conversion.
     * @return                  Object current time converted according to 
     *                          given time. If any errors occur during the
     *                          conversion, string "<Not available>" is returned.
     *
     */
    std::string getDateString(const std::string &aStrftimeFormat = "%F %T %Z") const;


    /** Return the time in 'struct tm' format.
     *
     *
     * This call is a object wrapper for C library call: 
     * \code
     * struct tm *localtime(const time_t *timep);
     * \endcode
     *
     * (See more information about fields 'man localtime');
     *
     * This function takes a copy of the data in that returned pointer
     * and returns it.
     * 
     * For quick help, 'struct tm' contains the following fields:
     *
     * \code
     * struct tm {
     *   int tm_sec;         - seconds
     *   int tm_min;         - minutes 
     *   int tm_hour;        - hours
     *   int tm_mday;        - day of the month
     *   int tm_mon;         - month
     *   int tm_year;        - year
     *   int tm_wday;        - day of the week
     *   int tm_yday;        - day in the year
     *   int tm_isdst;       - daylight saving time
     * };
     * \endcode
     *
     * @param[out] aTm          Reference to 'struct tm' containing 
     *                          the broken down time.
     * @return                  'true' when time was succesfully stored,
     *                          'false' on any error.
     *
     */
    bool getLocalTime(struct tm &aTm) const;


    /**
     * Returns the time in seconds, converting it to double.
     * @return                  Converted time in seconds.
     */
    double getTimeInSeconds() const { return double(seconds) + 
					(double(useconds)/1000000.00); }
    /**
     * Print the time
     * @p *prefix If you wanna say something in front of print
     */
    void print(const char *prefix=NULL) const;
    /**
     * Set the time 
     * @p sec The seconds
     * @p usec Microseconds
     */

    void set(const long int sec, const long int usec);
    /**
     * Set the time using struct timeval
     * @p t the timeval structure
     */
    //void set(struct timeval t);
    
    /// Overloaded operations for easier use.
    const time& operator= (const time& right);
    time& operator+= (const time& right);
    time& operator-= (const time& right);
    time operator+ (const time& right) const;
    time operator- (const time& right) const;
    bool operator== (const time& right) const;
    bool operator< (const time& right) const;
    bool operator> (const time& right) const;
    
 public: // Data members
    long int seconds;
    long int useconds;
};

/**
 * \class version
 * Structure to store version-information of program.
 */
class version {
  public:
    /**
    * Initializes with zeroes.
    */
    version();
    
    /**
    * Takes in version in the form MAJOR*10000 + MINOR*100 + EXTRA
    * and converts it to a more readable version.
    */
    version(int aVersion,
            int aBuild);
    
    /**
     * Initialize with separate version numbers.
     */
    version(int aMajorVersion,
            int aMinorVersion,
            int aExtraVersion,
            int aBuild);
    
    /**
     * Destructor
     */
    ~version();
    
    inline int getVersion() const { return compVersion; }
    inline int getMajorVersion() const { return majorVersion; }
    inline int getMinorVersion() const { return minorVersion; }
    inline int getExtraVersion() const { return extraVersion; }
    inline int getBuild() const { return build; }
    
    /**
     * Set new value for version.
     * 
     * \param[in] aVersion Version in format MAJOR*10000 + MINOR*100 + EXTRA
     * \param[in] aBuild Build number.
     * \return False if either parameter is <0, else true
     */
    bool setVersion(const int aVersion,
                    const int aBuild);
    
    std::string getVersionString() const;
    
    int compVersion; ///< Version information in form MAJOR*10000 + MINOR*100 + EXTRA
    int majorVersion; ///< Enables easier printing
    int minorVersion; ///< Enables easier printing
    int extraVersion; ///< Enables easier printing
    int build; ///< Build
};

} // end namespace gim

#endif // GIM_UTILS_H
